#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/boot.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>

//Baudrate(bps)
#define BAUDRATE           19200

//calculate baudrate register
#define BAUDREG            ((unsigned int)((F_CPU * 10) / (16UL * BAUDRATE) - 5) / 10)

//check baudrate register error
//mocro below maybe not same in different C compiler
#define FreqTemp           (16UL * BAUDRATE * (((F_CPU * 10) / (16 * BAUDRATE) + 5)/ 10))
#if ((FreqTemp * 50) > (51 * F_CPU)) || ((FreqTemp * 50) < (49 * F_CPU))
#error "BaudRate error > 2% ! Please check BaudRate and F_CPU value."
#endif

//internal use macro
#define CONCAT(a, b)       a ## b
#define CONCAT3(a, b, c)   a ## b ## c

//register of PORT and bit define
#define PORTREG(No)        CONCAT(PORT, No)
#define PINREG(No)         CONCAT(PIN, No)
#define UDRREG(No)         CONCAT(UDR, No)
#define DDRREG(No)         CONCAT(DDR, No)
#define TXCBIT(No)         CONCAT(TXC, No)
#define RXCBIT(No)         CONCAT(RXC, No)
#define RXENBIT(No)        CONCAT(RXEN, No)
#define TXENBIT(No)        CONCAT(TXEN, No)
#define URSELBIT(No)       CONCAT(URSEL, No)

//comport register
#define UBRRHREG(No)       CONCAT3(UBRR, No, H)
#define UBRRLREG(No)       CONCAT3(UBRR, No, L)
#define UCSRAREG(No)       CONCAT3(UCSR, No, A)
#define UCSRBREG(No)       CONCAT3(UCSR, No, B)
#define UCSRCREG(No)       CONCAT3(UCSR, No, C)
#define UCSZBIT(No1, No2)  CONCAT3(UCSZ, No1, No2)

//some kind of AVR need URSEL define when comport initialize
#if defined(URSEL) || defined(URSEL0)
#define USEURSEL           (1 << URSELBIT(COMPORTNo))
#else
#define USEURSEL           0
#endif

//define UART0 register
#if !defined(UDR0)
#define UBRR0H             UBRRH
#define UBRR0L             UBRRL
#define UCSR0A             UCSRA
#define UCSR0B             UCSRB
#define UCSR0C             UCSRC
#define UDR0               UDR
#define TXC0               TXC
#define RXC0               RXC
#define RXEN0              RXEN
#define TXEN0              TXEN
#define UCSZ01             UCSZ1
#define UCSZ00             UCSZ0
#define URSEL0             URSEL
#endif




#define WRITE(port, dat)							\
	UDRREG(port) = dat;                           	\
	while(!(UCSRAREG(port) & (1<<TXCBIT(port)))); 	\
	UCSRAREG(port) |= (1 << TXCBIT(port));        	\

#define INIT( port, baud)                                                      \
	UCSRAREG(port) = 0;                                                        \
	UCSRBREG(port) = (1 << RXENBIT(port))|(1 << TXENBIT(port));                \
	UCSRCREG(port) = USEURSEL|(1 << UCSZBIT(port, 1))|(1 << UCSZBIT(port, 0)); \
	UBRRHREG(port) = baud/256;                                                 \
	UBRRLREG(port) = baud%256;                                                 \


struct FIFO
{
	unsigned char ini;
	unsigned char len;
	unsigned char fifo[16];
} fifo_TX, fifo_RX;


void fifo_Init( struct FIFO *pF )
{
	pF->ini=0;
	pF->len=0;
}

void fifo_Put( struct FIFO *pF, char c )
{
	if ( pF->len < 16 )
	{
		pF->fifo[ ( pF->ini + pF->len ) & 0xf ] = c;
		pF->len++;
	}
}

unsigned char fifo_Get( struct FIFO *pF )
{
	char c = 0;
	if ( pF->len > 0 )
	{
		c = pF->fifo[ pF->ini & 0xf ];
		pF->ini++;
		pF->len--;
	}

	return c;
}

ISR(USART0_UDRE_vect)
{
	UDR0 = fifo_Get( &fifo_TX );
}

ISR(USART0_RX_vect)
{
	fifo_Put( &fifo_RX, UDR0 );
}



void SerialCOM1_Write( char dat)             
{
	WRITE(0,dat);
	//fifo_Put( &fifo_TX, dat );

/*
	if ( fifo_TX.len == 0)
	{
		UDR0 = dat;
	}
	else
	{
		fifo_Put( &fifo_TX, dat );
	}
*/
}

//initialize comport
void SerialCOM1_Init()                                                         
{       
	fifo_Init( &fifo_TX );
	fifo_Init( &fifo_RX );

	INIT( 0, BAUDREG);                                                                                   

    // Set the transmission speed for USART0. 
	//UBRR0H = ((((FOSC/16)/BAUD)-1)>>8);
	//UBRR0L = ((FOSC/16)/BAUD)-1;
	
    // Set the frame format for USART0. 8-data bits, 1-stop bit, no parity.
	UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
	
    // Enable the receiver, transmitter and receive interrupt of the USART0.
	UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);



}

char SerialCOM1_DR() 
{       
	//return (UCSRAREG(0) & (1 << RXCBIT(0))); 
	return fifo_RX.len>0;
}

char SerialCOM1_Read() 
{
	return fifo_Get( &fifo_RX );
    //return UDRREG(0);
}



